﻿using Castle.Core.Internal;
using Castle.DynamicProxy;
using Frame.Core.Common.Attributes;
using Frame.Core.Common.Common;
using Frame.Core.Common.Extensions;
using FreeSql;
using NLog;
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Frame.Core.Aop
{
    public class TransactionInterceptor : IInterceptor
    {
        IUnitOfWork _unitOfWork;
        private readonly UnitOfWorkManager _unitOfWorkManager;
        public Logger logger = LogManager.GetCurrentClassLogger();

        public TransactionInterceptor(UnitOfWorkManager unitOfWorkManager)
        {
            _unitOfWorkManager = unitOfWorkManager;
        }

        public void Intercept(IInvocation invocation)
        {
            var method = invocation.MethodInvocationTarget ?? invocation.Method;
            if (method.GetCustomAttributes(typeof(TransactionAttribute), false).FirstOrDefault() is TransactionAttribute)
            {
                InterceptTransaction(invocation, method);
            }
            else
            {
                invocation.Proceed();
            }
        }

        private void InterceptTransaction(IInvocation invocation, MethodInfo method)
        {
            try
            {
                var transaction = method.GetAttribute<TransactionAttribute>();
                _unitOfWork = _unitOfWorkManager.Begin(transaction.Propagation, transaction.IsolationLevel);
                invocation.Proceed();

                // 异步获取异常，先执行
                if (IsAsyncMethod(invocation.Method))
                {
                    var result = invocation.ReturnValue;
                    if (result is Task)
                    {
                        Task.WaitAll(result as Task);
                    }
                }


                _unitOfWork?.Commit();
            }
            catch (Exception ex)
            {
                _unitOfWork?.Rollback();
                ConsoleHelper.WriteWarningLine($"事务回滚,错误信息为:{ex.Message}");
                logger.Warn($"时间:{DateTime.Now},类型为:事务回滚,错误信息为:{ex.Message}");
            }
            finally
            {
                _unitOfWork?.Dispose();
            }
        }
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return (
                method.ReturnType == typeof(Task) ||
                (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
                );
        }
    }

}
